

#include "gamedatamanager.h"
#include "gamemanager.h"
#include "resourcemanager.h"
#include "strutil.h"


GameDataManager* GameDataManager::_instance = 0;


GameDataManager* GameDataManager::getInstance() {
	if (_instance == 0) { 
		_instance = new GameDataManager();
	}
	return _instance;
}


GameDataManager::GameDataManager() : money(0) {

}

GameDataManager::~GameDataManager() {

}

void GameDataManager::init() {
	loadUnitData();

//	loadAchievementData();
//	loadTalentData();
}

void GameDataManager::parseXmlNode(tinyxml2::XMLElement *xe, const char *tag, int& v) {
	auto node = xe->FirstChildElement(tag);
	if(node) {
		const char *s = node->GetText();
		if (s) {
			v = atoi(s);
		}
	}
}

void GameDataManager::parseXmlNode(tinyxml2::XMLElement *xe, const char *tag, float& v) {
	auto node = xe->FirstChildElement(tag);
	if(node) {
		const char *s = node->GetText();
		if (s) {
			v = static_cast<float>(atof(s));
		}
	}
}

void GameDataManager::parseXmlNode(tinyxml2::XMLElement *xe, const char *tag, string& v) {
	auto node = xe->FirstChildElement(tag);
	if(node) {	
		const char *s = node->GetText();
		if (s) {
			v = s;
		}
	}
}

SkillType GameDataManager::parseSkillType( const char* s )
{
	SkillType ret = SkillType::st_count;
	if(s) {
		for(int i = 0; i < (int)SkillType::st_count; i++) {
			if(strcmp(s, SKILL_TYPE_NAMES[i]) == 0) {
				ret = (SkillType)i;
				break;
			}
		}
	}

	return ret;
}

void GameDataManager::parseGameObjectAttribute( tinyxml2::XMLElement* xe, GameObjectAttribute& attr )
{
	int ret = strcmp(xe->FirstChildElement("attack_range")->GetText(), "melee");
	attr.attackRangeType = (ret == 0 ? AttackRange::melee : AttackRange::ranged);
	ret = strcmp(xe->FirstChildElement("multi_target_type")->GetText(), "single");
	attr.multiTargetType = (ret == 0 ? MultiTargetType::single : MultiTargetType::multiple);

	parseXmlNode(xe, "scale", attr.scale);
	parseXmlNode(xe, "speed", attr.speed);
	parseXmlNode(xe, "melee_damage", attr.meleeDamage);
	parseXmlNode(xe, "ranged_damage", attr.rangedDamage);
	parseXmlNode(xe, "melee_range", attr.meleeRange);
	parseXmlNode(xe, "range", attr.range);
	parseXmlNode(xe, "damage_range", attr.damageRange);
	parseXmlNode(xe, "interval", attr.interval);
	parseXmlNode(xe, "duration", attr.duration);
	parseXmlNode(xe, "health", attr.health);
	parseXmlNode(xe, "shield", attr.shield);

	parseXmlNode(xe, "interval", attr.skillAttribute.interval);
	parseXmlNode(xe, "chance", attr.skillAttribute.chance);
	parseXmlNode(xe, "range", attr.skillAttribute.range);
	parseXmlNode(xe, "duration", attr.skillAttribute.duration);
	parseXmlNode(xe, "value", attr.skillAttribute.value);

	attr.skillAttribute.type = parseSkillType(xe->FirstChildElement("skill_type")->GetText());
}

void GameDataManager::loadUnitData()
{
	using namespace tinyxml2;

	string xml = RM->loadTextFile("data/units.xml");

	tinyxml2::XMLDocument doc;
	doc.Parse(xml.c_str());

	XMLElement* root = doc.FirstChildElement("data");

	// load enemy data
	XMLElement* xeEnemy = root->FirstChildElement("enemy");
	XMLElement* item = xeEnemy ->FirstChildElement("i");

	while(item){
		string name = item->FirstChildElement("unit_name")->GetText();
		strutil::toLowerCase(name);

		GameObjectAttribute attr;
		parseGameObjectAttribute(item, attr);

		unitsAttribute.insert(make_pair(name, attr));

		item = item->NextSiblingElement("i");
	}

	log("loaded monster data");

	// load hero data
	XMLElement* xeHero = root->FirstChildElement("hero");
	item = xeHero ->FirstChildElement("i");
	while(item){
		string name = item->FirstChildElement("unit_name")->GetText();
		strutil::toLowerCase(name);

		GameObjectAttribute attr;
		parseGameObjectAttribute(item, attr);
		unitsAttribute.insert(make_pair(name, attr));

		item = item->NextSiblingElement("i");
	}

	log("loaded hero data");
}

void GameDataManager::loadAchievementData()
{
	using namespace tinyxml2;

	string xml = RM->loadTextFile("data/achievement.xml");

	tinyxml2::XMLDocument doc;
	doc.Parse(xml.c_str());

	XMLElement* root = doc.FirstChildElement("data");

	// load achievement data
	XMLElement* item = root ->FirstChildElement("i");
	while(item){
		AchievementInfo info;
		info.key = item->Attribute("key");
		info.title = item->Attribute("title");
		info.text = item->Attribute("text");
		info.bonus = item->FloatAttribute("bonus");
		info.request = item->IntAttribute("request");
		achievements.insert(make_pair(info.key, info));

		item = item->NextSiblingElement("i");
	}

	log("loaded achievement data");
}

void GameDataManager::loadTalentData()
{
	using namespace tinyxml2;
	tinyxml2::XMLDocument doc;

	string xml = RM->loadTextFile("data/talent.xml");
	doc.Parse(xml.c_str());

	XMLElement* root = doc.FirstChildElement("talent");
	XMLElement* item = root->FirstChildElement("node");
	while(item){
		TalentItem node;
		node.key = item->Attribute("k");
		node.x = X_SCALE(item->IntAttribute("x"));
		node.y = Y_SCALE(item->IntAttribute("y"));
		node.maxLevel = item->IntAttribute("max_level");

		parseXmlNode(item, "title", node.title);
		parseXmlNode(item, "text", node.text);

		XMLElement* xeValue1 = item->FirstChildElement("value1");
		if(xeValue1 && xeValue1->GetText()) {
			string s = xeValue1->GetText();
			vector<string> arr = strutil::split(s, ",");
			for(size_t i = 0; i < arr.size(); i++) {
				node.arrValue1.push_back(atof(arr[i].c_str()));
			}
		}
		XMLElement* xeValue2 = item->FirstChildElement("value2");
		if(xeValue2 && xeValue2->GetText()) {
			string s = xeValue2->GetText();
			vector<string> arr = strutil::split(s, ",");
			for(size_t i = 0; i < arr.size(); i++) {
				node.arrValue2.push_back(atof(arr[i].c_str()));
			}
		}
		XMLElement* xeValue3 = item->FirstChildElement("value3");
		if(xeValue3 && xeValue3->GetText()) {
			string s = xeValue3->GetText();
			vector<string> arr = strutil::split(s, ",");
			for(size_t i = 0; i < arr.size(); i++) {
				node.arrValue3.push_back(atof(arr[i].c_str()));
			}
		}
		XMLElement* xeValue4 = item->FirstChildElement("value4");
		if(xeValue4 && xeValue4->GetText()) {
			string s = xeValue4->GetText();
			vector<string> arr = strutil::split(s, ",");
			for(size_t i = 0; i < arr.size(); i++) {
				node.arrValue4.push_back(atof(arr[i].c_str()));
			}
		}
		XMLElement* xeValue5 = item->FirstChildElement("value5");
		if(xeValue5 && xeValue5->GetText()) {
			string s = xeValue5->GetText();
			vector<string> arr = strutil::split(s, ",");
			for(size_t i = 0; i < arr.size(); i++) {
				node.arrValue5.push_back(atof(arr[i].c_str()));
			}
		}
		XMLElement* xeCost = item->FirstChildElement("cost");
		if(xeCost && xeCost->GetText()) {
			string s = xeCost->GetText();
			vector<string> arr = strutil::split(s, ",");
			for(size_t i = 0; i < arr.size(); i++) {
				node.arrUpgradeCost.push_back(arr[i].c_str());
			}
		}

		XMLElement* parentsNode = item->FirstChildElement("parents");
		XMLElement* parentItem = parentsNode->FirstChildElement("i");
		while(parentItem) {
			node.parents.push_back(make_pair(parentItem->Attribute("k"), parentItem->IntAttribute("request_level")));
			parentItem = parentItem->NextSiblingElement();
		}

		talentsAttribute.insert(make_pair(node.key, node));

		item = item->NextSiblingElement("node");
	}

	log("loaded talent data");
}
